package org.dxy.domain.handler.route;

import com.google.common.eventbus.EventBus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.IEventRepository;
import org.dxy.domain.port.CommandHandler;
import org.dxy.domain.port.repository.IRouteRepository;
import org.dxy.domain.command.route.RouteAssignProcessesCommand;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.model.aggregate.Route;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: 工艺路线分配工序命令处理器
 * @author: dxy
 * @createTime: 2025/6/26 10:30
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RouteAddStepCommandHandler implements CommandHandler<RouteAssignProcessesCommand, Void> {

    private final IRouteRepository routeRepository;
    private final EventBus eventBus;
    private final IEventRepository eventRepository;

    @Transactional
    @Override
    public CommandResult<Void> handle(RouteAssignProcessesCommand command) {
        try {
            // 1. 查找工艺路线聚合根
            Route route = routeRepository.findById(command.routeId());
            if (route == null) {
                log.error("未找到工艺路线，routeId={}", command.routeId());
                return CommandResult.fail("工艺路线不存在");
            }

            // 2. 执行业务操作（分配工序）
            route.assignProcesses(command);

            // 3. 保存聚合根
            routeRepository.save(route);

            List<DomainEvent> events = route.getDomainEvents();

            // 4. 保存事件到事件存储，获取固定的事件ID列表
            List<Long> eventIds = eventRepository.saveEvents(events);

            // 5. 创建事件副本用于发布
            List<DomainEvent> eventsCopy = new ArrayList<>(events);

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    // 使用事务提交前保存的事件副本
                    eventsCopy.forEach(eventBus::post);

                    // 当事件发布成功后，会把这个字段标记为 true；（如果系统崩溃或重启，可以扫描未发布的事件（published = false）重新发布，保证"最终一致性"。）
                    eventRepository.markEventsPublished(eventIds);

                    // 7. 清理事件
                    route.clearDomainEvents();
                }
            });

            log.info("工艺路线工序分配成功, routeId={}, processIds={}", command.routeId(), command.processIds());
            return CommandResult.success("工艺路线工序分配成功");
            
        } catch (IllegalStateException | IllegalArgumentException e) {
            log.warn("工艺路线工序分配失败，原因：{}", e.getMessage());
            return CommandResult.fail(e.getMessage());
        } catch (Exception e) {
            log.error("工艺路线工序分配异常", e);
            return CommandResult.fail("工艺路线工序分配失败");
        }
    }
} 